package com.alibaba.yinan.graph;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.jgrapht.Graph;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.AsSubgraph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @ClassName NodeOccupancyManager
 * @Description 节点占用管理器（支持点位/机器/组，组内互斥）
 */
@Slf4j
@Service
public class NodeOccupancyManager {

    // 点位 -> 机器
    private final Map<String, String> nodeToMachine = new ConcurrentHashMap<>();

    // 机器 -> 点位集合
    private final Map<String, Set<String>> machineToNodes = new ConcurrentHashMap<>();

    // 组 -> 点位集合
    private final Map<String, Set<String>> groupToNodes = new ConcurrentHashMap<>();

    // 点位 -> 所属组
    private final Map<String, String> nodeToGroup = new ConcurrentHashMap<>();

    /**
     * 注册点位组
     */
    public void registerGroup(String groupId, Collection<String> nodes) {
        groupToNodes.put(groupId, new HashSet<>(nodes));
        nodes.forEach(node -> nodeToGroup.put(node, groupId));
        log.info("注册点位组 {} : {}", groupId, nodes);
    }

    /**
     * 占用一批点位（会自动占用所在组）
     */
    public synchronized boolean occupyNodes(String machineId, Collection<String> nodes) {
        log.info("机器 {} 尝试占用点位: {}", machineId, nodes);

        // 收集涉及的组
        Set<String> groups = nodes.stream()
                .map(nodeToGroup::get)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        // 收集组内所有点位（互斥扩展）
        Set<String> allNodesToLock = groups.stream()
                .map(groupToNodes::get)
                .filter(Objects::nonNull)
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());

        // 检查冲突
        List<String> conflicts = allNodesToLock.stream()
                .filter(node -> {
                    String m = nodeToMachine.get(node);
                    return m != null && !m.equals(machineId);
                })
                .collect(Collectors.toList());

        if (!conflicts.isEmpty()) {
            log.warn("机器 {} 占用失败，冲突点位: {}", machineId, conflicts);
            return false;
        }

        // 占用节点
        for (String node : allNodesToLock) {
            nodeToMachine.put(node, machineId);
            machineToNodes.computeIfAbsent(machineId, k -> ConcurrentHashMap.newKeySet()).add(node);
        }

        log.info("机器 {} 成功占用组 {}, 实际点位: {}", machineId, groups, allNodesToLock);
        return true;
    }

    /**
     * 释放节点（自动释放所在组）
     */
    public synchronized void releaseNodes(String machineId, Collection<String> nodes) {
        log.info("机器 {} 尝试释放点位: {}", machineId, nodes);

        Set<String> groups = nodes.stream()
                .map(nodeToGroup::get)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        Set<String> allNodesToRelease = groups.stream()
                .map(groupToNodes::get)
                .filter(Objects::nonNull)
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());

        for (String node : allNodesToRelease) {
            nodeToMachine.computeIfPresent(node, (n, m) -> m.equals(machineId) ? null : m);
        }

        Set<String> set = machineToNodes.get(machineId);
        if (set != null) {
            set.removeAll(allNodesToRelease);
            if (set.isEmpty()) {
                machineToNodes.remove(machineId);
            }
        }

        log.info("机器 {} 释放组 {}, 实际点位: {}", machineId, groups, allNodesToRelease);
    }

    /**
     * 查询某点位占用者
     */
    public Optional<String> getMachineByNode(String nodeId) {
        return Optional.ofNullable(nodeToMachine.get(nodeId));
    }

    /**
     * 查询某机器占用的所有点位
     */
    public Set<String> getNodesByMachine(String machineId) {
        return machineToNodes.getOrDefault(machineId, Collections.emptySet());
    }

    /**
     * 获取当前所有被占用的点位
     */
    public Set<String> getAllOccupiedNodes() {
        return new HashSet<>(nodeToMachine.keySet());
    }

    /**
     * 释放所有点位（系统重置/任务终止时调用）
     */
    public synchronized void clear() {
        nodeToMachine.clear();
        machineToNodes.clear();
        log.info("已释放所有点位占用状态");
    }

}
